import React, { useState, useEffect } from 'react';
import './App.css';
import ConnectionManager from './services/ConnectionManager';
import SettingsManager from './services/SettingsManager';
import ContactList from './components/ContactList';
import ChatArea from './components/ChatArea';
import FileTransferPanel from './components/FileTransferPanel';
import MediaCallPanel from './components/MediaCallPanel';
import Settings from './components/Settings';

function App() {
  const [connectionManager] = useState(() => new ConnectionManager());
  const [settingsManager] = useState(() => new SettingsManager());
  const [connected, setConnected] = useState(false);
  const [connecting, setConnecting] = useState(true);
  const [peers, setPeers] = useState([]);
  const [selectedPeer, setSelectedPeer] = useState(null);
  const [messages, setMessages] = useState([]);
  const [loadingMessages, setLoadingMessages] = useState(false);
  const [fileTransfers, setFileTransfers] = useState([]);
  const [incomingCall, setIncomingCall] = useState(null);
  const [activeCall, setActiveCall] = useState(null);
  const [error, setError] = useState(null);
  const [showSettings, setShowSettings] = useState(false);

  // Auto-hide error notifications after 5 seconds
  useEffect(() => {
    if (error) {
      const timer = setTimeout(() => {
        setError(null);
      }, 5000);
      return () => clearTimeout(timer);
    }
  }, [error]);

  useEffect(() => {
    // Define all event handlers
    const handleConnected = () => {
      setConnected(true);
      setConnecting(false);
    };

    const handleDisconnected = () => {
      setConnected(false);
      setConnecting(false);
    };
    const handlePeerList = (peerList) => setPeers(peerList);

    const handleMessage = (message) => {
      setMessages(prev => {
        // Avoid duplicate messages using messageId
        const exists = prev.some(m => m.messageId === message.messageId);
        if (exists) return prev;
        return [...prev, message];
      });
    };

    const handleFileIncoming = (fileData) => {
      setFileTransfers(prev => {
        // Avoid duplicate transfers
        const exists = prev.some(t => t.fileId === fileData.fileId);
        if (exists) return prev;
        return [...prev, fileData];
      });
    };

    const handleFileTransferStart = (fileData) => {
      setFileTransfers(prev => [...prev, fileData]);
    };

    const handleFileTransferComplete = (data) => {
      setFileTransfers(prev => prev.map(t =>
        t.fileId === data.fileId ? { ...t, status: 'completed' } : t
      ));
    };

    const handleFileTransferFailed = (data) => {
      setFileTransfers(prev => prev.map(t =>
        t.fileId === data.fileId ? { ...t, status: 'failed', error: data.error } : t
      ));
    };

    const handleIncomingCall = (callData) => setIncomingCall(callData);

    const handleCallRinging = (data) => {
      console.log('Call ringing:', data);
    };

    const handleCallFailed = (data) => {
      setError({ level: 'error', type: 'call', message: `Call failed: ${data.reason}` });
    };

    const handleCallTimeout = (data) => {
      setError({ level: 'warning', type: 'call', message: 'Call timeout - peer did not respond' });
    };

    const handleFileTransferError = (data) => {
      setError({ level: 'error', type: 'file', message: `File transfer failed: ${data.error}` });
    };

    const handleDiscoveryFailed = (data) => {
      setError({ level: 'error', type: 'connection', message: 'Cannot find server on network. Please ensure the server is running.' });
    };

    const handleFileTransferProgress = (data) => {
      setFileTransfers(prev => prev.map(t =>
        t.fileId === data.fileId ? { ...t, progress: data.progress, loaded: data.loaded, total: data.total } : t
      ));
    };

    // Register all event handlers
    connectionManager.on('connected', handleConnected);
    connectionManager.on('disconnected', handleDisconnected);
    connectionManager.on('peer-list', handlePeerList);
    connectionManager.on('message', handleMessage);
    connectionManager.on('file-incoming', handleFileIncoming);
    connectionManager.on('file-transfer-start', handleFileTransferStart);
    connectionManager.on('file-transfer-complete', handleFileTransferComplete);
    connectionManager.on('file-transfer-failed', handleFileTransferFailed);
    connectionManager.on('incoming-call', handleIncomingCall);
    connectionManager.on('call-ringing', handleCallRinging);
    connectionManager.on('call-failed', handleCallFailed);
    connectionManager.on('call-timeout', handleCallTimeout);
    connectionManager.on('discovery-failed', handleDiscoveryFailed);
    connectionManager.on('file-transfer-progress', handleFileTransferProgress);

    connectionManager.connect();

    return () => {
      // Remove all event listeners to prevent memory leaks
      connectionManager.off('connected', handleConnected);
      connectionManager.off('disconnected', handleDisconnected);
      connectionManager.off('peer-list', handlePeerList);
      connectionManager.off('message', handleMessage);
      connectionManager.off('file-incoming', handleFileIncoming);
      connectionManager.off('file-transfer-start', handleFileTransferStart);
      connectionManager.off('file-transfer-complete', handleFileTransferComplete);
      connectionManager.off('file-transfer-failed', handleFileTransferFailed);
      connectionManager.off('incoming-call', handleIncomingCall);
      connectionManager.off('call-ringing', handleCallRinging);
      connectionManager.off('call-failed', handleCallFailed);
      connectionManager.off('call-timeout', handleCallTimeout);
      connectionManager.off('discovery-failed', handleDiscoveryFailed);
      connectionManager.off('file-transfer-progress', handleFileTransferProgress);

      connectionManager.disconnect();
    };
  }, [connectionManager]);

  // Load message history when peer is selected
  useEffect(() => {
    if (selectedPeer && connectionManager) {
      const loadHistory = async () => {
        setLoadingMessages(true);
        try {
          const history = await connectionManager.loadMessageHistory(selectedPeer.id);
          if (history && history.length > 0) {
            setMessages(prev => {
              // Merge history with existing messages, avoiding duplicates using messageId
              const messageMap = new Map();

              // Add history messages to map
              history.forEach(msg => {
                const id = msg.message_id || msg.messageId;
                if (id) {
                  messageMap.set(id, msg);
                }
              });

              // Add existing messages to map (they take priority if same messageId)
              prev.forEach(msg => {
                const id = msg.message_id || msg.messageId;
                if (id) {
                  messageMap.set(id, msg);
                }
              });

              // Convert map to array and sort by timestamp
              return Array.from(messageMap.values()).sort((a, b) =>
                (a.timestamp || 0) - (b.timestamp || 0)
              );
            });
          }
        } catch (error) {
          console.error('Failed to load message history:', error);
          setError({ level: 'error', type: 'history', message: 'Failed to load message history' });
        } finally {
          setLoadingMessages(false);
        }
      };
      loadHistory();
    }
  }, [selectedPeer, connectionManager]);

  const handleSendMessage = (content, type = 'text') => {
    if (!selectedPeer) return;

    connectionManager.sendMessage(selectedPeer.id, content, type);
  };

  const handleSendFile = async (file) => {
    if (!selectedPeer) return;

    try {
      await connectionManager.sendFile(selectedPeer.id, file);
    } catch (error) {
      console.error('Failed to send file:', error);
      setError({ level: 'error', type: 'file', message: `Failed to send file: ${error.message}` });
    }
  };

  const handleStartCall = (type) => {
    if (!selectedPeer) return;

    connectionManager.startCall(selectedPeer.id, type);
    setActiveCall({ peer: selectedPeer, type });
  };

  const handleAcceptCall = () => {
    if (!incomingCall) return;

    const peer = peers.find(p => p.id === incomingCall.from);
    connectionManager.acceptCall(incomingCall.from, incomingCall.callType);
    setActiveCall({ peer, type: incomingCall.callType });
    setIncomingCall(null);
  };

  const handleRejectCall = () => {
    if (!incomingCall) return;

    connectionManager.rejectCall(incomingCall.from);
    setIncomingCall(null);
  };

  const handleEndCall = () => {
    connectionManager.endCall();
    setActiveCall(null);
  };

  const handleDownloadFile = (fileId, fileName) => {
    connectionManager.downloadFile(fileId, fileName);
  };

  return (
    <div className="App">
      {/* Initial connection loading overlay */}
      {connecting && !connected && (
        <div className="loading-overlay">
          <div className="loading-spinner"></div>
          <div className="loading-text">Connecting to server...</div>
        </div>
      )}

      {error && (
        <div className="error-notification">
          <div className={`error-content ${error.level || 'error'}`}>
            <strong>{error.type.toUpperCase()}</strong>: {error.message}
            <button className="error-close" onClick={() => setError(null)}>×</button>
          </div>
        </div>
      )}

      <div className="app-header">
        <h1>LANChat</h1>
        <div className="header-actions">
          <div className="connection-status">
            <span className={`status-indicator ${connecting ? 'connecting' : (connected ? 'connected' : 'disconnected')}`}></span>
            <span>{connecting ? 'Connecting...' : (connected ? 'Connected' : 'Disconnected')}</span>
          </div>
          <button className="settings-btn" onClick={() => setShowSettings(true)} title="设置">
            ⚙️
          </button>
        </div>
      </div>

      <div className="app-container">
        <ContactList
          peers={peers}
          selectedPeer={selectedPeer}
          onSelectPeer={setSelectedPeer}
        />

        <ChatArea
          peer={selectedPeer}
          messages={messages.filter(m => {
            const myId = connectionManager.clientId;
            const peerId = selectedPeer?.id;

            // Show messages where I sent to this peer OR this peer sent to me
            return (m.from === myId && m.to === peerId) ||
                   (m.from === peerId && m.to === myId) ||
                   (m.sender_id === peerId && m.peer_id === myId) ||
                   (m.sender_id === myId && m.peer_id === peerId);
          })}
          loadingMessages={loadingMessages}
          onSendMessage={handleSendMessage}
          onSendFile={handleSendFile}
          onStartCall={handleStartCall}
        />

        <FileTransferPanel
          transfers={fileTransfers.filter(t => {
            const myId = connectionManager.clientId;
            const peerId = selectedPeer?.id;

            // Show transfers where I sent to this peer OR this peer sent to me
            return (t.from === myId && t.to === peerId) ||
                   (t.from === peerId && t.to === myId) ||
                   (t.senderId === myId && t.peerId === peerId) ||
                   (t.senderId === peerId && t.peerId === myId);
          })}
          onDownload={handleDownloadFile}
        />
      </div>

      {incomingCall && (
        <div className="incoming-call-modal">
          <div className="modal-content">
            <h2>Incoming {incomingCall.callType} call</h2>
            <p>From: {peers.find(p => p.id === incomingCall.from)?.name || 'Unknown'}</p>
            <div className="call-actions">
              <button className="accept-btn" onClick={handleAcceptCall}>Accept</button>
              <button className="reject-btn" onClick={handleRejectCall}>Reject</button>
            </div>
          </div>
        </div>
      )}

      {activeCall && (
        <MediaCallPanel
          peer={activeCall.peer}
          callType={activeCall.type}
          onEndCall={handleEndCall}
          connectionManager={connectionManager}
        />
      )}

      {showSettings && (
        <Settings
          settingsManager={settingsManager}
          onClose={() => setShowSettings(false)}
        />
      )}
    </div>
  );
}

export default App;
